home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
EDITOR
/
TDE20E.ARJ
/
DIRLIST.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-05
|
28KB
|
851 lines
/*
* I wrote this function because I'm so stupid, I constantly forget
* file names and directory stuff. The main function prompts for a
* subdirectory name or a search path. The default search path is the
* cwd (current working directory). In addition to being stupid, I'm also
* lazy. If the user types a subdirectory name, I think we can assume he
* wants to list all files w/o having to type *.* Let's save the cwd on
* whatever drive the user wishes to search, so we can restore it we get
* thru dir'ing. Use the standard DOS functions to get and set directories.
*
* The search pattern can contain wild card chars, valid file names, or
* a valid subdirectory name.
*
* New editor name: tde, the Thomson-Davis Editor.
* Author: Frank Davis
* Date: June 5, 1991, version 1.0
* Date: July 29, 1991, version 1.1
* Date: October 5, 1991, version 1.2
* Date: January 20, 1992, version 1.3
* Date: February 17, 1992, version 1.4
* Date: April 1, 1992, version 1.5
* Date: June 5, 1992, version 2.0
*
* This code is released into the public domain, Frank Davis.
* You may distribute it freely.
*/
#include "tdestr.h"
#include "common.h"
#include "define.h"
#include "tdefunc.h"
#include <malloc.h>
/*
* Name: dir_help
* Purpose: To prompt the user and list the directory contents
* Date: February 13, 1992
* Passed: window: pointer to current window
*/
int dir_help( WINDOW *window )
{
char dname[MAX_COLS+2]; /* directory search pattern */
char stem[MAX_COLS+2]; /* directory stem */
int rc;
un_copy_line( window->cursor, window, TRUE );
dname[0] = '\0';
/*
* search path or pattern
*/
if (get_name( dir1,
window->bottom_line, dname, g_display.message_color ) == OK) {
if (validate_path( dname, stem ) == OK) {
rc = list_and_pick( dname, stem, window );
/*
* if everything is everything, load in the file selected by user.
*/
if (rc == OK)
attempt_edit_display( dname, LOCAL );
} else
/*
* invalid path or file name
*/
error( WARNING, window->bottom_line, dir2 );
}
return( OK );
}
/*
* Name: validate_path
* Purpose: make sure we got a valid search pattern or subdirectory
* Date: February 13, 1992
* Passed: dname: search path entered by user
* stem: directory stem is returned
* Returns: successful or not
* Notes: we need to validate the search path or pattern. if the search
* pattern is valid, then we need to get the search stem.
* the user may enter a subdirectory or some kind of search pattern.
* if the user enters a subdirectory, then there are a few things
* we need to take care of 1) find out if the subdirectory is
* the root, 2) append a '\' to the subdirectory so we can create
* a search pattern for the subdirectory, 3) don't append '\' to
* the root, it already has a '\'.
* if the user enters a search pattern, then we need to dissect the
* search path. we must create a stem from the search pattern.
*/
int validate_path( char *dname, char *stem )
{
int rc;
DTA dta; /* temp disk transfer struct for findfirst, etc. */
int fattr;
int i;
int len;
char *p;
char temp[MAX_COLS+2]; /* directory stem */
/*
* if path name is void then the current working directory is implied.
*/
if (dname[0] == '\0') {
strcpy( dname, stardotstar );
stem[0] = '\0';
rc = OK;
} else {
/*
* get the attributes of the search pattern, so we can determine if
* this is a pattern or subdirectory.
*/
rc = get_fattr( dname, &fattr );
if (rc == OK && (fattr & SUBDIRECTORY)) {
strcpy( stem, dname );
/*
* if this is the root directory ( \ ), don't append '\' to it.
* user entered a subdirectory - append *.* to get contents of
* subdirectory.
*/
len = strlen( stem );
if (stem[len-1] != '\\') {
strcat( stem, "\\" );
strcat( dname, "\\" );
}
strcat( dname, stardotstar );
/*
* not a subdirectory. let's see if any files match the search
* pattern.
*/
} else if (rc != ERROR) {
if ((rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN |
SYSTEM | SUBDIRECTORY | ARCHIVE )) == OK) {
/*
* copy dname to "temp" so we can use "temp" to find the stem.
* we need to search the pattern backwards to figure the stem.
*/
strcpy( temp, dname );
len = strlen( dname );
for (i=len,p=temp+len; i>=0; i--) {
/*
* if we run into the '\' or the ':', then we got a stem.
*/
if (*p == '\\' || *p == ':') {
p = temp + i;
*(p+1) = '\0';
break;
/*
* if we're at the beginning of the string, stem == '\0'
*/
} else if (i == 0) {
*p = '\0';
break;
}
--p;
}
strcpy( stem, temp );
} else
rc = ERROR;
/*
* user did not enter a valid subdirectory name or search pattern.
*/
} else
rc = ERROR;
}
return( rc );
}
/*
* Name: list_and_pick
* Purpose: To show matching file names and let user pick a file
* Date: February 13, 1992
* Passed: dname: directory search pattern
* stem: stem of directory search pattern
* window: pointer to current window
* Returns: return code from pick. rc = OK, then edit a new file.
* Notes: real work routine of this function. save the cwd and let the
* user search upwards or downwards thru the directory structure.
* since we are doing DOS directory functions, we need to check the
* return code after each DOS call for critical errors.
*/
int list_and_pick( char *dname, char *stem, WINDOW *window )
{
int rc;
DTA dta; /* disk transfer address for findfirst */
DIRECTORY dir; /* contains all info for dir display */
unsigned int cnt; /* number of matching files */
FTYPE *flist, *p; /* pointer to list of matching files */
char cwd[MAX_COLS]; /* save the current working directory in this buff */
char dbuff[MAX_COLS]; /* temporary directory buff */
char prefix[MAX_COLS]; /* directory prefix */
int change_directory = FALSE;
int stop;
int len;
int drive;
/*
* Some algorithms alloc the maximum possible number of files in
* a directory, eg. 256 or 512. Let's count the number of matching
* files so we know egxactly how much memory to request from calloc.
* Depending on the op system, disk media, disk format, or version of DOS,
* the max number of files may vary, anyway, also, additionally.
*/
rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM |
SUBDIRECTORY | ARCHIVE );
if (rc != ERROR) {
for (cnt=1; (rc = findnext( &dta )) == OK;)
++cnt;
flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
}
if (rc != ERROR && flist != NULL) {
stop = FALSE;
/*
* If user entered drive name in search pattern, find out the drive and
* directory stem.
*/
if (stem[1] == ':') {
/*
* If the second character of the search pattern is a ':', the
* the first character of the pattern should be the drive.
* Convert drive to lower case and get a numerical representation.
* CAVEAT: In DOS v 2.x, there may be up to 63 logical drives.
* this algorithm may blow up if the number of logical drives
* is greater than 'Z'.
* For DOS >= 3, the number of drives is limited to 26, I think.
*/
drive = stem[0];
if (drive < 'a')
drive += 32;
drive = drive - 'a' + 1;
rc = get_current_directory( dbuff, drive );
if (rc == ERROR)
stop = TRUE;
else {
/*
* Put drive letter, ':', and '\' in front of current directory.
*/
prefix[0] = (char)(drive - 1 + 'a');
prefix[1] = ':';
prefix[2] = '\\';
prefix[3] = '\0';
strcpy( cwd, prefix );
strcat( cwd, dbuff );
}
/*
* else get current directory from default drive
*/
} else {
/*
* 0 = default drive.
*/
drive = 0;
rc = get_current_directory( dbuff, drive );
if (rc == ERROR)
stop = TRUE;
else {
/*
* Put a '\' in front of the current directory.
*/
prefix[0] = '\\';
prefix[1] = '\0';
strcpy( cwd, prefix );
strcat( cwd, dbuff );
}
}
save_screen( );
while (stop == FALSE) {
/*
* If we had enough memory, find all matching file names. Append
* '\\' at the end of subdirectory names so user will know if
* name is a directory. Might as well find everything, because
* i also forget subdirectory names, too.
*
* when we get here, we have already done: 1) findfirst and findnext,
* 2) counted the number of matching files, and 3) allocated space.
*/
p = flist;
cnt = 0;
rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM |
SUBDIRECTORY | ARCHIVE );
if (rc != ERROR) {
/*
* p is pointer that walks down the file info structure.
* save the file name, file size, and directory character,
* if needed, for each matching file we find.
*/
strcpy( p->fname, dta.name );
p->fsize = dta.size;
if (dta.attrib & SUBDIRECTORY)
strcat( p->fname, "\\" );
for (cnt=1; (rc = findnext( &dta )) == OK; ) {
++p;
strcpy( p->fname, dta.name );
p->fsize = dta.size;
if (dta.attrib & SUBDIRECTORY)
strcat( p->fname, "\\" );
cnt++;
}
}
if (rc != ERROR) {
shell_sort( flist, cnt );
/*
* figure out number of rows, cols, etc... then display dir list
*/
setup_directory_window( &dir, cnt );
write_directory_list( flist, dir );
/*
* Let user select file name or another search directory.
* Save the choice in dbuff. rc == OK if user selected file or dir.
*/
rc = select_file( flist, stem, &dir );
strcpy( dbuff, flist[dir.select].fname );
}
/*
* give memory back.
*/
free( flist );
if (rc == ERROR)
stop = TRUE;
else {
len = strlen( dbuff );
/*
* If the last character in a file name is '\' then let's
* do a dir on selected directory. See the matching
* else when the user selects a file.
*/
if (dbuff[len-1] == '\\') {
/*
* Stem has subdirectory path. dbuff has selected path.
* Create a new dname with stem and dbuff.
*/
strcpy( dname, stem );
strcat( dname, dbuff );
len = strlen( dname );
strcpy( dbuff, dname );
/*
* The last character in dbuff is '\', because we append the
* '\' to every directory entry in the file list. Replace
* it with a NULL char then we will have a valid path name.
*/
dbuff[len-1] = '\0';
/*
* now let's change to the selected subdirectory.
*/
rc = set_current_directory( dbuff );
if (rc == OK) {
/*
* Every time we change directories, we need to get the
* current directory so we will be sure to have the
* correct path.
*/
rc = get_current_directory( dbuff, drive );
if (rc == OK) {
strcpy( dname, prefix );
strcat( dname, dbuff );
change_directory = TRUE;
}
}
/*
* Validate the new path and allocate memory for the
* matching files.
*/
if (rc == OK)
rc = validate_path( dname, stem );
if (rc == OK) {
rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN |
SYSTEM | SUBDIRECTORY | ARCHIVE );
if (rc != ERROR) {
for (cnt=1; (rc = findnext( &dta )) == OK;)
++cnt;
flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
}
}
if (flist == NULL || rc == ERROR) {
stop = TRUE;
rc = ERROR;
}
} else {
/*
* user selected a file. store fname in dname and return.
*/
rc = OK;
stop = TRUE;
strcpy( dname, stem );
strcat( dname, dbuff );
}
}
}
/*
* Go back to the current directory if needed.
*/
if (change_directory)
set_current_directory( cwd );
restore_screen( );
} else {
/*
* out of memory
*/
error( WARNING, window->bottom_line, dir3 );
rc = ERROR;
}
return( rc );
}
/*
* Name: setup_directory_window
* Purpose: set number of rows and cols in directory window
* Date: February 13, 1992
* Passed: dir: pointer to directory structure
* cnt: number of files
* Notes: set up stuff we need to know about how to display files.
*/
void setup_directory_window( DIRECTORY *dir, int cnt )
{
int i;
int wid;
char temp[MAX_COLS]; /* line to output */
/*
* setup the fixed vars used in dir display.
* dir->col = physical upper left column of dir screen
* dir->row = physical upper left row or line of dir screen
* dir->wid = width of physical screen
* dir->hgt = height of physical screen
* dir->max_cols number of columns of files in dir screen
* dir->max_lines number of lines of files in each column in dir screen
* dir->cnt number of files in list
*/
dir->col = 3;
dir->row = 5;
wid = dir->wid = 72;
dir->hgt = 16;
dir->max_cols = 5;
dir->max_lines = 9;
dir->cnt = cnt;
/*
* Find out how many lines in each column are needed to display
* matching files.
*/
dir->lines = dir->cnt / dir->max_cols + (dir->cnt % dir->max_cols ? 1 : 0);
if (dir->lines > dir->max_lines)
dir->lines = dir->max_lines;
/*
* Find out how many columns of file names we need.
*/
dir->cols = dir->cnt / dir->lines + (dir->cnt % dir->lines ? 1 : 0);
if (dir->cols > dir->max_cols)
dir->cols = dir->max_cols;
/*
* Find the maximun number of file names we can display in help screen.
*/
dir->avail = dir->lines * dir->cols;
/*
* Now find the number of file names we do have on the screen. Every
* time we slide the "window", we have to calculate a new nfiles.
*/
dir->nfiles = dir->cnt > dir->avail ? dir->avail : dir->cnt;
/*
* A lot of times, the number of matching files will not fit evenly
* in our help screen. The last column on the right will be partially
* filled, hence the variable name prow (partial row). When there are
* more file names than can fit on the screen, we have to calculate
* prow every time we slide the "window" of files.
*/
dir->prow = dir->lines - (dir->avail - dir->nfiles);
/*
* Find out how many "virtual" columns of file names we have. If
* all the files can fit in the dir screen, there will be no
* virtual columns.
*/
if (dir->cnt < dir->avail)
dir->vcols = 0;
else
dir->vcols = (dir->cnt - dir->avail) / dir->max_lines +
((dir->cnt - dir->avail) % dir->max_lines ? 1 : 0);
/*
* Find the physical display column in dir screen.
*/
dir->flist_col[0] = dir->col + 2;
for (i=1; i<dir->max_cols; i++)
dir->flist_col[i] = dir->flist_col[i-1] + 14;
/*
* Now, draw the borders of the dir screen.
*/
for (i=0; i < dir->hgt; i++) {
if (i == 0 || i == dir->hgt-1) {
memset( temp, '─', wid );
temp[wid] = '\0';
if (i == 0) {
temp[0] = '┌';
temp[wid-1] = '┐';
} else {
temp[0] = '└';
temp[wid-1] = '┘';
}
} else {
memset( temp, ' ', wid );
temp[wid] = '\0';
temp[0] = temp[wid-1] = '│';
}
s_output( temp, dir->row+i, dir->col, g_display.help_color );
}
/*
* Write headings in help screen.
*/
s_output( dir4, dir->row+1, dir->col+3, g_display.help_color );
s_output( dir5, dir->row+2, dir->col+3, g_display.help_color );
s_output( dir6, dir->row+2, dir->col+44, g_display.help_color );
s_output( dir7, dir->row+14, dir->col+8, g_display.help_color );
}
/*
* Name: write_directory_list
* Purpose: given directory list, display matching files
* Date: February 13, 1992
* Passed: flist: pointer to list of files
* dir: directory display structure
* Notes: blank out the previous file name and display the new one.
*/
void write_directory_list( FTYPE *flist, DIRECTORY dir )
{
FTYPE *p, *top;
int i;
int j;
int k;
int end;
int line;
int col;
int color;
color = g_display.help_color;
top = flist;
for (i=0; i < dir.lines; ++i) {
p = top;
end = FALSE;
for (j=0; j < dir.cols; ++j) {
col = dir.flist_col[j];
line = i + dir.row + 4;
/*
* We need to blank out all lines and columns used to display
* files, because there may be some residue from a previous dir
*/
s_output( " ", line, col, color );
if (!end) {
s_output( p->fname, line, col, color );
p += dir.lines;
k = p - flist;
if (k >= dir.nfiles)
end = TRUE;
}
}
++top;
}
}
/*
* Name: select_file
* Purpose: To let user select a file from dir list
* Date: February 13, 1992
* Passed: flist: pointer to list of files
* stem: base directory
* dir: directory display stuff
* Notes: let user move thru the file names with the cursor keys
*/
int select_file( FTYPE *flist, char *stem, DIRECTORY *dir )
{
int ch; /* input character from user */
int func; /* function of character input by user */
int fno; /* index into flist of the file under cursor */
int goodkey; /* is key a recognized function key? */
int r; /* current row of cursor */
int c; /* current column of cursor */
int offset; /* offset into file list */
int stop; /* stop indicator */
int stem_len; /* stem length */
int color; /* color of help screen */
int file_color; /* color of current file */
int change; /* boolean, hilite another file? */
int oldr; /* old row */
int oldc; /* old column */
char asize[20]; /* ascii file size */
char blank[20]; /* blank out file names */
/*
* initial everything.
*/
memset( blank, ' ', 12 );
blank[12] = '\0';
c = r = 1;
ch = fno = offset = 0;
color = g_display.help_color;
file_color = g_display.hilited_file;
goodkey = TRUE;
stop = FALSE;
stem_len = strlen( stem );
s_output( stem, dir->row+1, dir->col+19, color );
s_output( flist[fno].fname, dir->row+1, dir->col+19+stem_len, color );
ltoa( flist[fno].fsize, asize, 10 );
s_output( blank, dir->row+2, dir->col+19, color );
s_output( asize, dir->row+2, dir->col+19, color );
itoa( dir->cnt, asize, 10 );
s_output( blank, dir->row+2, dir->col+57, color );
s_output( asize, dir->row+2, dir->col+57, color );
xygoto( (c-1)*14+dir->col+2, r+dir->row+3 );
hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color );
change = FALSE;
while (stop == FALSE) {
oldr = r;
oldc = c;
ch = getkey( );
func = getfunc( ch );
/*
* User may have redefined the Enter and ESC keys. Make the Enter key
* perform a Rturn in this function. Make the ESC key do an AbortCommand.
*/
if (ch == RTURN)
func = Rturn;
else if (ch == ESC)
func = AbortCommand;
switch (func) {
case Rturn :
case NextLine :
case BegNextLine :
stop = TRUE;
break;
case AbortCommand :
stop = TRUE;
break;
case LineUp :
if (r > 1) {
change = TRUE;
--r;
} else {
r = dir->lines;
change = TRUE;
if (offset == 0 || c > 1) {
if (c > 1)
--c;
} else if (dir->vcols > 0 && offset > 0 && c == 1) {
/*
* recalculate the dir display stuff.
*/
offset -= dir->lines;
recalculate_dir( dir, flist, offset );
}
}
goodkey = TRUE;
break;
case LineDown :
if (r < dir->prow) {
change = TRUE;
++r;
} else if (r < dir->lines && c != dir->cols) {
change = TRUE;
++r;
} else {
change = TRUE;
r = 1;
if (offset == dir->vcols * dir->lines || c < dir->cols) {
if (c < dir->cols)
++c;
} else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
c == dir->cols) {
offset += dir->lines;
recalculate_dir( dir, flist, offset );
}
}
goodkey = TRUE;
break;
case CharLeft :
if (offset == 0 || c > 1) {
if (c > 1) {
change = TRUE;
--c;
}
} else if (dir->vcols > 0 && offset > 0 && c == 1) {
change = TRUE;
/*
* recalculate the dir display stuff.
*/
offset -= dir->lines;
recalculate_dir( dir, flist, offset );
}
goodkey = TRUE;
break;
case CharRight :
if (offset == dir->vcols * dir->lines || c < dir->cols) {
if (c < dir->cols) {
change = TRUE;
++c;
if (c == dir->cols) {
if ( r > dir->prow)
r = dir->prow;
}
}
} else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
c == dir->cols) {
change = TRUE;
offset += dir->lines;
recalculate_dir( dir, flist, offset );
if (r > dir->prow)
r = dir->prow;
}
goodkey = TRUE;
break;
case BegOfLine :
change = TRUE;
c = r = 1;
goodkey = TRUE;
break;
case EndOfLine :
change = TRUE;
r = dir->prow;
c = dir->cols;
goodkey = TRUE;
break;
case ScreenDown :
change = TRUE;
r = (c == dir->cols) ? r = dir->prow : dir->lines;
goodkey = TRUE;
break;
case ScreenUp :
change = TRUE;
r = 1;
goodkey = TRUE;
break;
}
if (goodkey) {
s_output( blank, dir->row+1, dir->col+19+stem_len, color );
fno = offset + (c-1)*dir->lines + (r-1);
s_output( flist[fno].fname, dir->row+1, dir->col+19+stem_len, color );
ltoa( flist[fno].fsize, asize, 10 );
s_output( blank, dir->row+2, dir->col+19, color );
s_output( asize, dir->row+2, dir->col+19, color );
xygoto( (c-1)*14+dir->col+2, r+dir->row+3 );
goodkey = FALSE;
if (change) {
hlight_line( (oldc-1)*14+dir->col+2, oldr+dir->row+3, 12, color );
hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color );
change = FALSE;
}
}
}
dir->select = fno;
return( func == AbortCommand ? ERROR : OK );
}
/*
* Name: recalculate_dir
* Purpose: To recalcute dir structure when cursor goes ahead or behind screen
* Date: February 13, 1992
* Passed: dir: pointer to file structure
* flist: pointer to file structure
* offset: number of files from beginning of flist
* Notes: Find new number of files on the screen. Then, find out
* how many files names are in the last column.
*/
void recalculate_dir( DIRECTORY *dir , FTYPE *flist, int offset )
{
register int off;
off = offset;
dir->nfiles = (dir->cnt - off) > dir->avail ? dir->avail :
(dir->cnt - off);
dir->prow = dir->lines - (dir->avail - dir->nfiles);
write_directory_list( flist+off, *dir );
}
/*
* Name: shell_sort
* Purpose: To sort file names
* Date: February 13, 1992
* Passed: flist: pointer to file structure
* cnt: number of files to sort
*/
void shell_sort( FTYPE *flist, int cnt )
{
register int i;
int inc;
int limit;
int change;
FTYPE temp;
FTYPE *fl;
fl = flist;
inc = cnt / 2;
while (inc) {
limit = cnt - inc - 1;
do {
change = FALSE;
for (i=0; i<=limit; i++) {
if (memcmp( fl[i].fname, fl[i+inc].fname, 14 ) > 0) {
memcpy( &temp, fl+i, sizeof(FTYPE) );
memcpy( fl+i, fl+i+inc, sizeof(FTYPE) );
memcpy( fl+i+inc, &temp, sizeof(FTYPE) );
change = i;
}
}
limit = change - inc;
} while (change);
inc = inc / 2;
}
}